package org.example.coursemangementserver.server.service.impl.student;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.example.coursemangementserver.common.constant.JwtClaimsConstant;
import org.example.coursemangementserver.common.context.BaseContext;
import org.example.coursemangementserver.common.exception.common.CommonException;
import org.example.coursemangementserver.common.properties.JwtProperties;
import org.example.coursemangementserver.common.utils.Aes;
import org.example.coursemangementserver.common.utils.JwtUtil;
import org.example.coursemangementserver.pojo.dto.IDListDTO;
import org.example.coursemangementserver.pojo.dto.UserLoginDTO;
import org.example.coursemangementserver.pojo.dto.UserRegisterDTO;
import org.example.coursemangementserver.pojo.dto.Pagination;
import org.example.coursemangementserver.pojo.dto.course.StudentCommentCourseDTO;
import org.example.coursemangementserver.pojo.dto.course.StudentCourseCommentListQuery.GetStudentCourseCommentListDTO;
import org.example.coursemangementserver.pojo.dto.course.StudentCourseListQuery.GetStudentCourseListDTO;
import org.example.coursemangementserver.pojo.dto.course.StudentCourseSelectListQuery.GetStudentCourseSelectListDTO;
import org.example.coursemangementserver.pojo.dto.course.StudentDropCourseDTO;
import org.example.coursemangementserver.pojo.dto.course.StudentSelectCourseDTO;
import org.example.coursemangementserver.pojo.dto.student.StudentListQuery.GetStudentListDTO;
import org.example.coursemangementserver.pojo.dto.student.StudentListQuery.QueryParams;
import org.example.coursemangementserver.pojo.dto.student.StudentNewInfoDTO;
import org.example.coursemangementserver.pojo.entity.CourseReview;
import org.example.coursemangementserver.pojo.entity.Enrollment;
import org.example.coursemangementserver.pojo.entity.SelectionInformation;
import org.example.coursemangementserver.pojo.entity.Student;
import org.example.coursemangementserver.pojo.vo.UserLoginVO;
import org.example.coursemangementserver.pojo.vo.course.StudentCourseList.StudentCourseListVO;
import org.example.coursemangementserver.pojo.vo.course.StudentCourseList.StudentCourseVO;
import org.example.coursemangementserver.pojo.vo.course.StudentSelectCourseList.StudentSelectCourseListVO;
import org.example.coursemangementserver.pojo.vo.course.StudentSelectCourseList.StudentSelectCourseVO;
import org.example.coursemangementserver.pojo.vo.course.studentCourseCommentList.StudentCourseCommentListVO;
import org.example.coursemangementserver.pojo.vo.course.studentCourseCommentList.StudentCourseCommentVO;
import org.example.coursemangementserver.pojo.vo.student.StudentAuditingInfoList.StudentAuditingListInfoVO;
import org.example.coursemangementserver.pojo.vo.student.StudentAuditingInfoVO;
import org.example.coursemangementserver.pojo.vo.student.StudentInfoList.StudentListVO;
import org.example.coursemangementserver.pojo.vo.student.StudentInfoVO;
import org.example.coursemangementserver.pojo.vo.student.StudentVO;
import org.example.coursemangementserver.server.mapper.CourseReviewMapper;
import org.example.coursemangementserver.server.mapper.EnrollmentMapper;
import org.example.coursemangementserver.server.mapper.SelectionInformationMapper;
import org.example.coursemangementserver.server.mapper.StudentMapper;
import org.example.coursemangementserver.server.service.interfac.student.StudentService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author 12438
 */
@Service
@Slf4j
public class StudentServiceImpl extends ServiceImpl<StudentMapper,Student> implements StudentService {

    @Autowired
    private StudentMapper  studentMapper;
    @Autowired
    private SelectionInformationMapper selectionInformationMapper;
    @Autowired
    private CourseReviewMapper courseReviewMapper;
    /**
     * 注入JWT令牌相关属性
     */
    @Autowired
    private JwtProperties jwtProperties;

    @Autowired
    private EnrollmentMapper enrollmentMapper;

    /**
     * 学生登录
     * @param userLoginDTO
     * @return
     */
    @Override
    public UserLoginVO login(UserLoginDTO userLoginDTO) {
        Student student  = studentMapper.selectByStudentNum(userLoginDTO.getUsername());
        String  password = Aes.decrypt(userLoginDTO.getPassword());
        if (student != null && student.getPassword().equals(password)) {
            if (student.getStatus() != 1) {
                throw new CommonException("您的账号正在审核或已被封禁，请联系管理员");
            }
            //登录成功后生成JWT令牌(封装账户id进令牌)
            Map<String, Object> claims = new HashMap<>();
            claims.put(JwtClaimsConstant.USER_ID, student.getStudentId());
            claims.put(JwtClaimsConstant.USERNAME, student.getStudentNum());
            String jwtToken = JwtUtil.createJwt(claims, jwtProperties.getStudentSecretKey(), jwtProperties.getExpireTime());
            log.info("学生登录成功，发放学生令牌：{}", jwtToken);
            return new UserLoginVO(student.getStudentId(),student.getStudentNum(),jwtToken,1,student.getName(),student.getAvatarUrl());
        } else {
            // 抛出异常向前端提示密码或用户名错误
            throw new CommonException("账号或密码错误，学生登录失败");
        }
    }

    /**
     * 学生提交注册申请
     * @param userRegisterDTO
     */
    @Override
    public void register(UserRegisterDTO userRegisterDTO) {
        userRegisterDTO.setPassword(Aes.decrypt(userRegisterDTO.getPassword()));
        Student student = new Student();
        BeanUtils.copyProperties(userRegisterDTO, student);
        student.setStudentNum(userRegisterDTO.getUsername());
        studentMapper.insert(student);
    }

    /**
     * 获取学生待审核信息
     * @return
     */
    @Override
    public StudentAuditingListInfoVO getStudentAuditing(Pagination pagination) {
        Integer start = (pagination.getCurrentPage()-1) * pagination.getPageSize();
        Integer total = studentMapper.getStudentAuditingCount();
        List<StudentAuditingInfoVO>  studentAuditingInfoVOList = studentMapper.getStudentAuditing(start,pagination.getPageSize());
        return new StudentAuditingListInfoVO(total,studentAuditingInfoVOList);
    }

    /**
     * 获取学生信息列表
     * @param getStudentListDTO
     * @return
     */
    @Override
    public StudentListVO getStudentList(GetStudentListDTO getStudentListDTO) {
        Pagination  pagination = getStudentListDTO.getPagination();
        Integer start = (pagination.getCurrentPage()-1) * pagination.getPageSize();
        QueryParams  queryParams = getStudentListDTO.getQueryParams();
        if (queryParams != null) {
            Integer total = studentMapper.getStudentTotal(queryParams.getName());
            List<StudentVO>  studentVOList = studentMapper.getStudentList(start,pagination.getPageSize(),queryParams.getName());
            return new StudentListVO(total,studentVOList);
        }
        Integer total = studentMapper.getStudentTotal(null);
        List<StudentVO>  studentVOList = studentMapper.getStudentList(start,pagination.getPageSize(),null);
        return new StudentListVO(total,studentVOList);
    }

    /**
     * 获取某个学生的所有可选课程信息列表
     * @param getStudentCourseSelectListDTO
     * @return
     */
    @Override
    public StudentSelectCourseListVO getStudentSelectCourse(GetStudentCourseSelectListDTO getStudentCourseSelectListDTO) {
        long studentId = BaseContext.getCurrentUser().getUserId();
        Student  student = studentMapper.getStudentById(studentId);
        Pagination pagination = getStudentCourseSelectListDTO.getPagination();
        Integer start = (pagination.getCurrentPage()-1)* pagination.getPageSize();
        org.example.coursemangementserver.pojo.dto.course.StudentCourseSelectListQuery.QueryParams queryParams =  getStudentCourseSelectListDTO.getQueryParams();
        if (queryParams != null){
            Integer total = enrollmentMapper.getStudentSelectCourseTotal(student.getStudentId(),student.getGrade(),queryParams.getName(),queryParams.getTeacherName());
            List<StudentSelectCourseVO>  selectCourseList = enrollmentMapper.getStudentSelectCourseList(student.getStudentId(),start,pagination.getPageSize(),student.getGrade(),queryParams.getName(),queryParams.getTeacherName());
            return new  StudentSelectCourseListVO(total,selectCourseList);
        }
        Integer total = enrollmentMapper.getStudentSelectCourseTotal(student.getStudentId(),student.getGrade(),null,null);
        List<StudentSelectCourseVO>  selectCourseList = enrollmentMapper.getStudentSelectCourseList(student.getStudentId(),start,pagination.getPageSize(),student.getGrade(),null,null);
        return new  StudentSelectCourseListVO(total,selectCourseList);
    }

    /**
     * 处理学生选课
     * @param studentSelectCourseDTO
     */
    @Override
    public void studentSelectCourse(StudentSelectCourseDTO studentSelectCourseDTO) {
        // 获取进行选课的学生的信息
        Student student = studentMapper.getStudentById(BaseContext.getCurrentUser().getUserId());
        // 获取待选课程信息
        Enrollment  enrollment = enrollmentMapper.getEnrollmentById(studentSelectCourseDTO.getEnrollmentId());
        // 进行验证，看是否容量超过了，以及学生年级是否符合要求
        if (enrollment.getMaxNum() <= enrollment.getPresentNum()){
            // 容量超过了,抛出异常
            throw new CommonException("容量不足，选课失败");
        }
        if (!Objects.equals(student.getGrade(), enrollment.getGrade())){
            // 年级不符合要求，抛出异常
            throw new CommonException("您所在年级不符合要求，选课失败");
        }
        if (!(enrollment.getMinCredits()<=student.getLearnCredits() && student.getLearnCredits()<=enrollment.getMaxCredits())){
            // 学分不符合要求，抛出异常
            throw new CommonException("您的学分不符合要求，选课失败");
        }
        // 查看它所选的已有课程是否会与该课程产生冲突
        Integer total = selectionInformationMapper.getStudentCourseTotal(BaseContext.getCurrentUser().getUserId(),null,null);
        List<StudentCourseVO> studentCourseList = selectionInformationMapper.getStudentCourseList(0,total,BaseContext.getCurrentUser().getUserId(),null,null);
        Integer week = enrollment.getWeek();
        Integer onClass = enrollment.getOnClass();
        for (StudentCourseVO studentCourseVO : studentCourseList) {
            if (Objects.equals(studentCourseVO.getWeek(), week) && Objects.equals(studentCourseVO.getOnClass(), onClass)){
                // 冲突，抛出异常   TODO
                throw new CommonException("课程冲突，选课失败");
            }
        }
        // 进行选课
        enrollment.setPresentNum(enrollment.getPresentNum()+1);
        enrollmentMapper.updateById(enrollment);
        // 查找是否原先有选课记录
        SelectionInformation selectionInformation = selectionInformationMapper.getSelectionInformationByEnrollmentIdAndStudentId(student.getStudentId(),enrollment.getEnrollmentId());
        if (selectionInformation != null){
            // 有选课记录，修改选课记录的状态为正常即可，不用新增
            selectionInformation.setStatus(1);
            selectionInformationMapper.updateById(selectionInformation);
            return;
        }
        // 生成选课记录
        selectionInformation = new SelectionInformation();
        selectionInformation.setCourseId(enrollment.getCourseId());
        selectionInformation.setStudentId(student.getStudentId());
        selectionInformation.setEnrollmentId(enrollment.getEnrollmentId());
        selectionInformationMapper.insert(selectionInformation);
    }

    /**
     * 学生查看自己的课程
     * @param getStudentCourseListDTO
     * @return
     */
    @Override
    public StudentCourseListVO getStudentCourseList(GetStudentCourseListDTO getStudentCourseListDTO) {
        Long studentId = BaseContext.getCurrentUser().getUserId();
        Pagination pagination = getStudentCourseListDTO.getPagination();
        Integer start = (pagination.getCurrentPage()-1)* pagination.getPageSize();
        org.example.coursemangementserver.pojo.dto.course.StudentCourseListQuery.QueryParams queryParams = getStudentCourseListDTO.getQueryParams();
        if(queryParams != null){
            Integer total = selectionInformationMapper.getStudentCourseTotal(studentId,queryParams.getName(),queryParams.getTeacherName());
            List<StudentCourseVO> studentCourseList = selectionInformationMapper.getStudentCourseList(start,pagination.getPageSize(),studentId,queryParams.getName(),queryParams.getTeacherName());
            return new StudentCourseListVO(total,studentCourseList);
        }
        Integer total = selectionInformationMapper.getStudentCourseTotal(studentId,null,null);
        List<StudentCourseVO> studentCourseList = selectionInformationMapper.getStudentCourseList(start,pagination.getPageSize(),studentId,null,null);
        return new StudentCourseListVO(total,studentCourseList);
    }

    /**
     * 处理学生退课
     * @param studentDropCourseDTO
     */
    @Override
    public void studentDropCourse(StudentDropCourseDTO studentDropCourseDTO) {
        // 查找选课记录信息
        SelectionInformation selectionInformation = selectionInformationMapper.getSelectionInformationById(studentDropCourseDTO.getSelectInfoId());
        // 修改选课记录信息(修改status状态为已退课)
        selectionInformation.setStatus(0);
        selectionInformationMapper.updateById(selectionInformation);
        // 修改待选课程信息（增加一个容量）
        Enrollment enrollment = enrollmentMapper.getEnrollmentById(selectionInformation.getEnrollmentId());
        enrollment.setPresentNum(enrollment.getPresentNum()-1);
        enrollmentMapper.updateById(enrollment);
    }

    /**
     * 学生获取已结课的未评价的课程信息
     * @param getStudentCourseListDTO
     * @return
     */
    @Override
    public StudentCourseCommentListVO getStudentCourseCommentList(GetStudentCourseCommentListDTO getStudentCourseListDTO) {
        Long studentId = BaseContext.getCurrentUser().getUserId();
        Pagination pagination = getStudentCourseListDTO.getPagination();
        Integer start = (pagination.getCurrentPage()-1)* pagination.getPageSize();
        org.example.coursemangementserver.pojo.dto.course.StudentCourseCommentListQuery.QueryParams queryParams = getStudentCourseListDTO.getQueryParams();
        if(queryParams != null){
            Integer total = selectionInformationMapper.getStudentCourseCommentTotal(studentId,queryParams.getName(),queryParams.getTeacherName());
            List<StudentCourseCommentVO> studentCourseList = selectionInformationMapper.getStudentCourseCommentList(start,pagination.getPageSize(),studentId,queryParams.getName(),queryParams.getTeacherName());
            return new StudentCourseCommentListVO(total,studentCourseList);
        }
        Integer total = selectionInformationMapper.getStudentCourseCommentTotal(studentId,null,null);
        List<StudentCourseCommentVO> studentCourseList = selectionInformationMapper.getStudentCourseCommentList(start,pagination.getPageSize(),studentId,null,null);
        return new StudentCourseCommentListVO(total,studentCourseList);
    }

    /**
     * 学生评价课程
     * @param studentCommentCourseDTO
     */
    @Override
    public void studentCommentCourse(StudentCommentCourseDTO studentCommentCourseDTO) {
        // 增加课程评价记录
        CourseReview courseReview = new CourseReview();
        courseReview.setCourseId(studentCommentCourseDTO.getCourseId());
        courseReview.setStudentId(BaseContext.getCurrentUser().getUserId());
        courseReview.setContent(studentCommentCourseDTO.getContent());
        courseReview.setRating(studentCommentCourseDTO.getRating());
        courseReview.setEnrollmentId(studentCommentCourseDTO.getEnrollmentId());
        courseReviewMapper.insert(courseReview);
        // 修改选课记录状态为已评价
        SelectionInformation selectionInformation = selectionInformationMapper.getSelectionInformationById(studentCommentCourseDTO.getSelectInfoId());
        selectionInformation.setCommentStatus(1);
        selectionInformationMapper.updateById(selectionInformation);
    }

    @Override
    public StudentInfoVO getStudentDetail() {
        Student student = studentMapper.getStudentById(BaseContext.getCurrentUser().getUserId());
        StudentInfoVO studentInfoVO = new StudentInfoVO();
        BeanUtils.copyProperties(student,studentInfoVO);
        return studentInfoVO;
    }

    @Override
    public void updateStudentInfo(StudentNewInfoDTO studentNewInfoDTO) {
        Student student = studentMapper.getStudentById(BaseContext.getCurrentUser().getUserId());
        student.setName(studentNewInfoDTO.getName());
        student.setAvatarUrl(studentNewInfoDTO.getAvatarUrl());
        student.setStudentNum(studentNewInfoDTO.getStudentNum());
        student.setGrade(studentNewInfoDTO.getGrade());
        if (studentNewInfoDTO.getPassword() != null){
            student.setPassword(Aes.decrypt(studentNewInfoDTO.getPassword()));
        }
        studentMapper.updateById(student);
    }

    @Override
    public void selectCourseOnList(IDListDTO idListDTO) {
        // 获取进行选课的学生的信息
        Student student = studentMapper.getStudentById(BaseContext.getCurrentUser().getUserId());
        for (Long id : idListDTO.getIds()) {
            // 获取待选课程信息
            Enrollment  enrollment = enrollmentMapper.getEnrollmentById(id);
            // 进行验证，看是否容量超过了，以及学生年级是否符合要求
            if (enrollment.getMaxNum() <= enrollment.getPresentNum()){
                // 容量超过了,抛出异常
                throw new CommonException("容量不足，选课失败");
            }
            if (student.getGrade() != enrollment.getGrade()){
                // 年级不符合要求，抛出异常
                throw new CommonException("您所在年级不符合要求，选课失败");
            }
            if (!(enrollment.getMinCredits()<=student.getLearnCredits() && student.getLearnCredits()<=enrollment.getMaxCredits())){
                // 学分不符合要求，抛出异常
                throw new CommonException("您的学分不符合要求，选课失败");
            }
            // 查看它所选的已有课程是否会与该课程产生冲突
            Integer total = selectionInformationMapper.getStudentCourseTotal(BaseContext.getCurrentUser().getUserId(),null,null);
            List<StudentCourseVO> studentCourseList = selectionInformationMapper.getStudentCourseList(0,total,BaseContext.getCurrentUser().getUserId(),null,null);
            Integer week = enrollment.getWeek();
            Integer onClass = enrollment.getOnClass();
            for (StudentCourseVO studentCourseVO : studentCourseList) {
                if (Objects.equals(studentCourseVO.getWeek(), week) && Objects.equals(studentCourseVO.getOnClass(), onClass)){
                    // 冲突，抛出异常   TODO
                    throw new CommonException("课程冲突，选课失败");
                }
            }
            // 进行选课
            enrollment.setPresentNum(enrollment.getPresentNum()+1);
            enrollmentMapper.updateById(enrollment);
            // 查找是否原先有选课记录
            SelectionInformation selectionInformation = selectionInformationMapper.getSelectionInformationByEnrollmentIdAndStudentId(student.getStudentId(),enrollment.getEnrollmentId());
            if (selectionInformation != null){
                // 有选课记录，修改选课记录的状态为正常即可，不用新增
                selectionInformation.setStatus(1);
                selectionInformationMapper.updateById(selectionInformation);
                continue;
            }
            // 生成选课记录
            selectionInformation = new SelectionInformation();
            selectionInformation.setCourseId(enrollment.getCourseId());
            selectionInformation.setStudentId(student.getStudentId());
            selectionInformation.setEnrollmentId(enrollment.getEnrollmentId());
            selectionInformationMapper.insert(selectionInformation);
        }
    }

    @Override
    public void studentDropCourseOnList(IDListDTO idListDTO) {
        for (Long id : idListDTO.getIds()) {
            // 查找选课记录信息
            SelectionInformation selectionInformation = selectionInformationMapper.getSelectionInformationById(id);
            // 修改选课记录信息(修改status状态为已退课)
            selectionInformation.setStatus(0);
            selectionInformationMapper.updateById(selectionInformation);
            // 修改待选课程信息（增加一个容量）
            Enrollment enrollment = enrollmentMapper.getEnrollmentById(selectionInformation.getEnrollmentId());
            enrollment.setPresentNum(enrollment.getPresentNum()-1);
            enrollmentMapper.updateById(enrollment);
        }
    }
}
